local M = {}
local util = require("lspconfig.util")

-- Windows平台URI格式处理
local function format_windows_uri(uri)
	local prefix = "file:///"
	if uri:sub(1, #prefix) == prefix then
		local path_part = uri:sub(#prefix + 1)
		-- 检查是否是Windows驱动器路径
		if path_part:match("^[A-Za-z]:") then
			-- 转换为小写驱动器字母并转义冒号
			local drive_letter = path_part:sub(1, 1):lower()
			local rest_path = path_part:sub(3)
			return prefix .. drive_letter .. "%3A" .. rest_path
		end
	end
	return uri
end

-- 获取capacities配置
local function get_capabilities()
	return vim.tbl_deep_extend("force", vim.lsp.protocol.make_client_capabilities(), {
		workspace = {
			didChangeWatchedFiles = {
				dynamicRegistration = true,
				relativePatternSupport = true,
			},
			configuration = true,
		},
		textDocument = {
			semanticTokens = {
				dynamicRegistration = true,
				requests = {
					range = true,
					full = { delta = true },
				},
				legend = {
					tokenTypes = {
						"comment",
						"keyword",
						"string",
						"number",
						"regexp",
						"operator",
						"namespace",
						"type",
						"struct",
						"class",
						"interface",
						"enum",
						"typeParameter",
						"function",
						"member",
						"property",
						"macro",
						"variable",
						"parameter",
						"label",
					},
					tokenModifiers = {
						"declaration",
						"documentation",
						"static",
						"abstract",
						"deprecated",
						"async",
						"readonly",
					},
				},
			},
			completion = {
				dynamicRegistration = true,
				completionItem = {
					snippetSupport = true,
					resolveSupport = {
						properties = { "documentation", "detail", "additionalTextEdits" },
					},
				},
				completionItemKind = {
					valueSet = {
						1,
						2,
						3,
						4,
						5,
						6,
						7,
						8,
						9,
						10,
						11,
						12,
						13,
						14,
						15,
						16,
						17,
						18,
						19,
						20,
						21,
						22,
						23,
						24,
						25,
					},
				},
			},
			codeAction = {
				dynamicRegistration = true,
				resolveSupport = {
					properties = { "edit" },
				},
				codeActionLiteralSupport = {
					codeActionKind = {
						valueSet = {
							"",
							"quickfix",
							"refactor",
							"refactor.extract",
							"refactor.inline",
							"refactor.rewrite",
							"source",
							"source.organizeImports",
						},
					},
				},
			},
			hover = {
				dynamicRegistration = true,
				contentFormat = { "markdown", "plaintext" },
			},
			definition = {
				dynamicRegistration = true,
				linkSupport = true,
			},
			references = {
				dynamicRegistration = true,
			},
			documentHighlight = {
				dynamicRegistration = true,
			},
			documentSymbol = {
				dynamicRegistration = true,
				hierarchicalDocumentSymbolSupport = true,
			},
			rename = {
				dynamicRegistration = true,
				prepareSupport = true,
			},
			signatureHelp = {
				dynamicRegistration = true,
				signatureInformation = {
					documentationFormat = { "markdown", "plaintext" },
					parameterInformation = { labelOffsetSupport = true },
					activeParameterSupport = true,
				},
			},
		},
	})
end

-- 使用 TOML 解析库解析文件
local function parse_toml_with_library(file_path)
	local TOML
	local ok = pcall(function()
		TOML = require("toml2lua")
	end)

	if not ok or not TOML then
		return nil
	end

	local success, parsed = pcall(function()
		return TOML.parse(vim.fn.readfile(file_path))
	end)

	return success and parsed or nil
end

-- 回退解析逻辑：解析 cjpm.toml
local function parse_cjpm_toml_fallback(file_path, new_root_dir)
	local package_name = "default"
	local dependencies = {}

	local toml_content = vim.fn.readfile(file_path)
	local in_package = false
	local in_dependencies = false

	for _, line in ipairs(toml_content) do
		if line:match("^%s*%[package%]%s*$") then
			in_package = true
			in_dependencies = false
		elseif line:match("^%s*%[dependencies%]%s*$") then
			in_dependencies = true
			in_package = false
		elseif line:match("^%s*%[") then
			in_package = false
			in_dependencies = false
		end

		if in_package then
			local name_match = line:match("^%s*name%s*=%s*['\"]([^'\"]+)['\"]")
			if name_match then
				package_name = name_match
			end
		end

		if in_dependencies then
			local dep_name, path_val = line:match("^%s*([%w_]+)%s*=%s*{.-path%s*=%s*['\"]([^'\"]+)['\"]")
			if dep_name and path_val then
				local abs_path = path_val:sub(1, 1) == "/" and path_val
					or vim.fn.fnamemodify(new_root_dir, ":p") .. path_val
				dependencies[dep_name] = {
					type = "path",
					path = vim.uri_from_fname(abs_path),
				}
			end

			local git_dep_name, git_url, git_branch =
				line:match("^%s*([%w_]+)%s*=%s*{.-git%s*=%s*['\"]([^'\"]+)['\"].-branch%s*=%s*['\"]([^'\"]+)['\"]")
			if git_dep_name and git_url then
				dependencies[git_dep_name] = {
					type = "git",
					git = git_url,
					branch = git_branch or "master",
				}
			end
		end
	end

	return { package_name = package_name, dependencies = dependencies }
end

-- 回退解析逻辑：解析 cjpm.lock
local function parse_cjpm_lock_fallback(file_path, dependencies)
	local lock_content = vim.fn.readfile(file_path)
	for _, line in ipairs(lock_content) do
		for dep_name, dep_info in pairs(dependencies) do
			if dep_info.type == "git" then
				local pattern = dep_name .. "%s*=%s*{.-commitId%s*=%s*['\"]([a-f0-9]+)['\"]"
				local commit_match = line:match(pattern)
				if commit_match then
					dep_info.commitId = commit_match
				end
			end
		end
	end
end

-- 使用 TOML 库解析 cjpm.toml
local function parse_cjpm_toml_with_library(file_path, new_root_dir)
	local parsed = parse_toml_with_library(file_path)
	if not parsed then
		return nil
	end

	local package_name = parsed.package and parsed.package.name or "default"
	local dependencies = {}

	if parsed.dependencies then
		for dep_name, dep_config in pairs(parsed.dependencies) do
			if type(dep_config) == "table" then
				if dep_config.path then
					local abs_path = dep_config.path:sub(1, 1) == "/" and dep_config.path
						or vim.fn.fnamemodify(new_root_dir, ":p") .. dep_config.path
					dependencies[dep_name] = {
						type = "path",
						path = vim.uri_from_fname(abs_path),
					}
				elseif dep_config.git then
					dependencies[dep_name] = {
						type = "git",
						git = dep_config.git,
						branch = dep_config.branch or "master",
					}
				end
			end
		end
	end

	return { package_name = package_name, dependencies = dependencies }
end

-- 使用 TOML 库解析 cjpm.lock
local function parse_cjpm_lock_with_library(file_path, dependencies)
	local parsed = parse_toml_with_library(file_path)
	if not parsed then
		return false
	end

	for dep_name, dep_info in pairs(dependencies) do
		if dep_info.type == "git" and parsed[dep_name] then
			dep_info.commitId = parsed[dep_name].commitId
		end
	end
	return true
end

-- 构建配置参数
local function build_config_params(new_config, new_root_dir, cj_home, is_windows)
	local home_dir = vim.fn.getenv("HOME")
	local package_name = "default"
	local dependencies = {}
	local requires = {}

	-- 解析 cjpm.toml
	local cjpm_toml_path = vim.fn.fnamemodify(new_root_dir, ":p") .. "cjpm.toml"
	if vim.fn.filereadable(cjpm_toml_path) == 1 then
		local result = parse_cjpm_toml_with_library(cjpm_toml_path, new_root_dir)
			or parse_cjpm_toml_fallback(cjpm_toml_path, new_root_dir)

		if result then
			package_name = result.package_name
			dependencies = result.dependencies
		end
	end

	-- 解析 cjpm.lock
	local cjpm_lock_path = vim.fn.fnamemodify(new_root_dir, ":p") .. "cjpm.lock"
	if vim.fn.filereadable(cjpm_lock_path) == 1 then
		local has_library = parse_cjpm_lock_with_library(cjpm_lock_path, dependencies)
		if not has_library then
			parse_cjpm_lock_fallback(cjpm_lock_path, dependencies)
		end
	end

	-- 构建 requires
	for dep_name, dep_info in pairs(dependencies) do
		if dep_info.type == "git" and dep_info.commitId then
			local git_path = home_dir .. "/.cjpm/git/" .. dep_name .. "/" .. dep_info.commitId
			requires[dep_name] = {
				git = dep_info.git,
				branch = dep_info.branch,
				path = vim.uri_from_fname(git_path),
			}
		elseif dep_info.type == "path" then
			requires[dep_name] = {
				path = dep_info.path,
			}
		end
	end

	-- 构建 multiModuleOption
	local multi_module_config = {}
	for dep_name, dep_info in pairs(requires) do
		if dep_info.git and dep_info.path then
			local uri = dep_info.path
			if is_windows then
				uri = format_windows_uri(uri)
			end
			multi_module_config[uri] = {
				name = dep_name,
				requires = {},
			}
		end
	end

	local root_uri = vim.uri_from_fname(new_root_dir)
	if is_windows then
		root_uri = format_windows_uri(root_uri)
	end
	multi_module_config[root_uri] = {
		name = package_name,
		requires = requires,
	}

	-- 环境变量设置 - 使用标准路径拼接
	local path_sep = is_windows and "\\" or "/"
	local path_delim = is_windows and ";" or ":"

	-- Windows下使用USERPROFILE替代HOME
	if is_windows and (not home_dir or home_dir == vim.NIL) then
		home_dir = vim.fn.getenv("USERPROFILE")
	end

	-- Windows下的库路径
	local runtime_lib_path = is_windows and "runtime\\lib\\windows_x86_64_llvm" or "runtime/lib/linux_x86_64_llvm"
	local cjpm_bin_path = is_windows and "cjpm\\bin" or ".cjpm/bin"

	new_config.cmd_env = {
		CANGJIE_HOME = cj_home,
		CANGJIE_PATH = table.concat({
			cj_home .. path_sep .. "bin",
			cj_home .. path_sep .. "tools" .. path_sep .. "bin",
			cj_home .. path_sep .. "debugger" .. path_sep .. "bin",
			home_dir .. path_sep .. cjpm_bin_path,
		}, path_delim),
		CANGJIE_LD_LIBRARY_PATH = table.concat({
			cj_home .. path_sep .. runtime_lib_path,
			cj_home .. path_sep .. "tools" .. path_sep .. "lib",
		}, path_delim),
		LD_LIBRARY_PATH = table.concat({
			cj_home .. path_sep .. runtime_lib_path,
			cj_home .. path_sep .. "tools" .. path_sep .. "lib",
			vim.env.LD_LIBRARY_PATH or "",
		}, path_delim),
		PATH = table.concat({
			cj_home .. path_sep .. "bin",
			cj_home .. path_sep .. "tools" .. path_sep .. "bin",
			cj_home .. path_sep .. "debugger" .. path_sep .. "bin",
			home_dir .. path_sep .. cjpm_bin_path,
			vim.env.PATH,
		}, path_delim),
	}

	-- 初始化选项
	new_config.init_options = {
		multiModuleOption = multi_module_config,
		modulesHomeOption = cj_home,
		stdLibPathOption = cj_home,
		targetLib = new_root_dir .. "/target/release",
		conditionCompileOption = {},
		singleConditionCompileOption = {},
		conditionCompilePaths = {},
		telemetryOption = true,
		extensionPath = cj_home,
		-- cangjieRootUri = vim.uri_from_fname(new_root_dir), -- 关键：激活DevEco模式
	}

	-- workspace folders
	local workspace_name = vim.fn.fnamemodify(new_root_dir, ":t")
	local workspace_uri = vim.uri_from_fname(new_root_dir)
	if is_windows then
		workspace_uri = format_windows_uri(workspace_uri)
	end
	new_config.workspace_folders = { {
		uri = workspace_uri,
		name = workspace_name,
	} }
end

function M.setup(opts)
	local cj_home = opts.cangjie_home or vim.env.CANGJIE_HOME or vim.env.CJVS_MULTISHELL_PATH
	if not cj_home or cj_home == "" or type(cj_home) ~= "string" then
		vim.notify("[Cangjie] CANGJIE_HOME environment variable is not set", vim.log.levels.ERROR)
		return
	end

	-- 处理Windows下的可执行文件扩展名
	local is_windows = vim.fn.has("win32") == 1 or vim.fn.has("win64") == 1
	local lsp_server_path = cj_home .. "/tools/bin/LSPServer"
	if is_windows then
		lsp_server_path = lsp_server_path .. ".exe"
	end
	if vim.fn.executable(lsp_server_path) == 0 then
		vim.notify("[Cangjie] LSPServer not found at: " .. lsp_server_path, vim.log.levels.ERROR)
		return
	end

	local capabilities = get_capabilities()

	-- 日志配置
	local enable_log = opts.enable_log ~= false -- 默认为true

	-- 基础配置
	local base_config = {
		cmd = { lsp_server_path, "-V" },
		filetypes = { "Cangjie" },
		root_dir = util.root_pattern("cjpm.toml"),
		single_file_support = false,
		capabilities = capabilities,
		on_new_config = function(new_config, new_root_dir)
			-- 配置日志参数
			local log_dir = opts.log_dir or new_root_dir
			if enable_log then
				table.insert(new_config.cmd, "--enable-log=true")
				table.insert(new_config.cmd, "--log-path=" .. log_dir)
			end
			build_config_params(new_config, new_root_dir, cj_home, is_windows)
		end,
	}

	-- local lspconfig = require("lspconfig")
	-- -- 如果是 Neovim ≥ 0.11 的 vim.lsp.config 写法
	-- vim.lsp.config("cangjie", base_config)
	-- vim.lsp.enable("cangjie")

	-- 注册配置
	if not require("lspconfig.configs")["cangjie-lsp"] then
		require("lspconfig.configs")["cangjie-lsp"] = {
			default_config = base_config,
		}
	end

	-- 标准lspconfig
	require("lspconfig")["cangjie-lsp"].setup(base_config)

	vim.notify("[Cangjie] LSP server configured successfully", vim.log.levels.INFO)
end

return M
